home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmbase-grok-1.2 / canvdraw.c < prev    next >
C/C++ Source or Header  |  1995-06-25  |  17KB  |  595 lines

  1. /*
  2.  * draw card canvas. This canvas is used by the form editor to allow the
  3.  * user to position items in a form and to set their size. The canvas is
  4.  * drawn using Xlib calls; items are represented by colored rectangles.
  5.  */
  6.  
  7. #include <X11/Xos.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <Xm/Xm.h>
  11. #include <Xm/DrawingA.h>
  12. #include <Xm/Protocols.h>
  13. #include <X11/cursorfont.h>
  14. #include "grok.h"
  15. #include "form.h"
  16. #include "proto.h"
  17.  
  18. #define XSNAP(x)    ((x)-(x)%form->xg)
  19. #define YSNAP(y)    ((y)-(y)%form->yg)
  20. #define DIV_WIDTH    2
  21. #define DIV_GRIPSZ    8
  22. #define DIV_GRIPOFF    12
  23.  
  24. static void quit_callback  (Widget, XtPointer, XmToggleButtonCallbackStruct *);
  25. static void expose_callback(Widget, XtPointer, XmDrawingAreaCallbackStruct *);
  26. static void resize_callback(Widget, XtPointer, XmDrawingAreaCallbackStruct *);
  27. static void canvas_callback(Widget, XButtonEvent *, String *, int);
  28. static void draw_rubberband(BOOL, int, int, int, int);
  29. static int  ifont(FONTN);
  30.  
  31. extern XtAppContext    app;        /* application handle, for actions */
  32. extern Display        *display;    /* everybody uses the same server */
  33. extern GC        gc;        /* everybody uses this context */
  34. extern GC        xor_gc;        /* XOR gc for rubberbanding */
  35. extern Pixel        color[NCOLS];    /* colors: COL_* */
  36. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  37. extern int        curr_item;    /* current item, 0..form.nitems-1 */
  38.  
  39. static BOOL        have_shell;    /* week window is being displayed */
  40. static FORM        *form;        /* current form, registered by create*/
  41. static Widget        shell;        /* entire window */
  42. static Widget        canvas;        /* drawing area */
  43.  
  44.  
  45. /*
  46.  * destroy the canvas window. Remove it from the screen, and destroy its
  47.  * widgets.
  48.  */
  49.  
  50. void destroy_canvas_window(void)
  51. {
  52.     if (have_shell) {
  53.         XtPopdown(shell);
  54.         XtDestroyWidget(shell);
  55.         have_shell = FALSE;
  56.     }
  57. }
  58.  
  59.  
  60. /*
  61.  * create the canvas window with a single DrawingArea in it. Find out how
  62.  * many pixels the window manager added for the window decoration around
  63.  * the drawing area, so we can figure out the new drawing area size from
  64.  * the new window size if the user resizes the window.
  65.  * The form pointer is saved in a static variable because the callbacks
  66.  * also need it, and I think it's easier to understand this way.
  67.  */
  68.  
  69. void create_canvas_window(
  70.     FORM        *f)
  71. {
  72.     Arg        args[15];
  73.     int        n;
  74.     Atom        closewindow;
  75.     XtActionsRec    action;
  76.     String        translations =
  77.         "<Btn1Down>:    canvas(down)    ManagerGadgetArm()    \n\
  78.          <Btn1Up>:    canvas(up)    ManagerGadgetActivate()    \n\
  79.          <Btn1Motion>:    canvas(motion)    ManagerGadgetButtonMotion()";
  80.  
  81.     destroy_canvas_window();
  82.     form = f;
  83.  
  84.     n = 0;
  85.     XtSetArg(args[n], XmNdeleteResponse,    XmDO_NOTHING);        n++;
  86.     XtSetArg(args[n], XmNiconic,        False);            n++;
  87.     shell = XtAppCreateShell("Form Editor Canvas", "Grok",
  88.             applicationShellWidgetClass, display, args, n);
  89.     set_icon(shell, 1);
  90.  
  91.     action.string = "canvas";
  92.     action.proc   = (XtActionProc)canvas_callback;
  93.     XtAppAddActions(app, &action, 1);
  94.  
  95.     n = 0;
  96.     XtSetArg(args[n], XmNwidth,        form->xs);        n++;
  97.     XtSetArg(args[n], XmNheight,        form->ys);        n++;
  98.     XtSetArg(args[n], XmNresizePolicy,    XmRESIZE_ANY);        n++;
  99.     XtSetArg(args[n], XmNtranslations,
  100.             XtParseTranslationTable(translations));        n++;
  101.  
  102.     canvas = XtCreateManagedWidget("canvas", xmDrawingAreaWidgetClass,
  103.             shell, args, n);
  104.     XtAddCallback(canvas, XmNexposeCallback,
  105.             (XtCallbackProc)expose_callback, (XtPointer)0);
  106.     XtAddCallback(canvas, XmNresizeCallback,
  107.             (XtCallbackProc)resize_callback, (XtPointer)0);
  108.  
  109.     XtPopup(shell, XtGrabNone);
  110.     closewindow = XmInternAtom(display, "WM_DELETE_WINDOW", False);
  111.     XmAddWMProtocolCallback(shell, closewindow,
  112.             (XtCallbackProc)quit_callback, (XtPointer)0);
  113.     set_cursor(canvas, XC_arrow);
  114.     have_shell = TRUE;
  115. }
  116.  
  117.  
  118. /*-------------------------------------------------- callbacks --------------*/
  119. /*
  120.  * All of these routines are direct X callbacks.
  121.  */
  122.  
  123. /*ARGSUSED*/
  124. static void quit_callback(
  125.     Widget                widget,
  126.     XtPointer            item,
  127.     XmToggleButtonCallbackStruct    *data)
  128. {
  129.     create_error_popup(shell, 0, "%s%s",
  130.         "Please press the Done button in the main\n",
  131.         "Form Editor window to remove this window.");
  132. }
  133.  
  134.  
  135. /*ARGSUSED*/
  136. static void expose_callback(
  137.     Widget                w,
  138.     XtPointer            data,
  139.     XmDrawingAreaCallbackStruct    *info)
  140. {
  141.     XEvent                dummy;
  142.     while (XCheckWindowEvent(display, info->window, ExposureMask, &dummy));
  143.     redraw_canvas();
  144. }
  145.  
  146.  
  147. /*ARGSUSED*/
  148. static void resize_callback(
  149.     Widget                w,
  150.     XtPointer            data,
  151.     XmDrawingAreaCallbackStruct    *info)
  152. {
  153.     XEvent                dummy;
  154.     Arg                args[2];
  155.     Dimension            xs=0, ys=0;
  156.  
  157.     while (XCheckWindowEvent(display, info->window,
  158.             ResizeRedirectMask, &dummy));
  159.     XtSetArg(args[0], XmNwidth,  &xs);
  160.     XtSetArg(args[1], XmNheight, &ys);
  161.     XtGetValues(canvas, args, 2);
  162.     form->xs = xs;
  163.     form->ys = ys;
  164.     redraw_canvas();
  165. }
  166.  
  167.  
  168. /*-------------------------------------------------- dragging ---------------*/
  169. /*
  170.  * mouse position classifications
  171.  */
  172.  
  173. typedef enum {
  174.     M_OUTSIDE = 0,        /* not near any item */
  175.     M_INSIDE,        /* inside an item, but not near an edge */
  176.     M_DIVIDER,        /* on grip between static part and card */
  177.     M_TOP,            /* near top edge */
  178.     M_BOTTOM,        /* near bottom edge */
  179.     M_LEFT,            /* near left edge */
  180.     M_RIGHT,        /* near right edge */
  181.     M_XMID,            /* near X divider in an input/date/time item */
  182.     M_YMID            /* near Y divider in a note/view item */
  183. } MOUSE;
  184.  
  185. static MOUSE locate_item(int *, int, int);
  186. static int cursorglyph[] = {
  187.     XC_X_cursor,
  188.     XC_fleur,
  189.     XC_sb_v_double_arrow,
  190.     XC_top_side,
  191.     XC_bottom_side,
  192.     XC_left_side,
  193.     XC_right_side,
  194.     XC_sb_h_double_arrow,
  195.     XC_sb_v_double_arrow
  196. };
  197.  
  198.  
  199. /*
  200.  * this routine is called directly from the drawing area's translation
  201.  * table, with mouse up/down/motion events.
  202.  */
  203.  
  204. /*ARGSUSED*/
  205. static void canvas_callback(
  206.     Widget        w,        /* widget, == canvas */
  207.     XButtonEvent    *event,        /* X event, contains position */
  208.     String        *args,        /* what happened, up/down/motion */
  209.     int        nargs)        /* # of args, must be 1 */
  210. {
  211.     static int    nitem;        /* item on which pen was pressed */
  212.     static MOUSE    mode;        /* what's being moved: M_* */
  213.     static int    down_x, down_y;    /* pos where pen was pressed down */
  214.     static int    state;        /* button/modkey mask when pressed */
  215.     static BOOL    moving;        /* this is not a selection, move box */
  216.     ITEM        *item;        /* item being selected or moved */
  217.     int        x, y, xs, ys;    /* new item start and size */
  218.     int        xm, ym;        /* new item midpoint division */
  219.     int        dx, dy;        /* movement since initial press */
  220.     int        i, nsel;
  221.  
  222.     if (!strcmp(args[0], "down")) {
  223.         down_x = event->x;
  224.         down_y = event->y;
  225.         state  = event->state;
  226.         moving = FALSE;
  227.         mode   = locate_item(&nitem, event->x, event->y);
  228.         set_cursor(canvas, cursorglyph[mode]);
  229.         return;
  230.     }
  231.     if (!strcmp(args[0], "motion") && (event->state & Button1Mask)
  232.                        && mode != M_OUTSIDE) {
  233.         x = abs(event->x - down_x);
  234.         y = abs(event->y - down_y);
  235.         moving |= x > 3 || y > 3;
  236.     }
  237.     if (moving) {
  238.         if (mode == M_OUTSIDE)
  239.             return;
  240.         if (mode == M_DIVIDER) {
  241.             x  = 0;
  242.             y  = event->y;
  243.             xs = form->xs;
  244.             ys = 1;
  245.         } else {
  246.             item = form->items[nitem];
  247.             x  = item->x;
  248.             y  = item->y;
  249.             xs = item->xs;
  250.             ys = item->ys;
  251.             xm = item->xm;
  252.             ym = item->ym;
  253.             dx = event->x - down_x;
  254.             dy = event->y - down_y;
  255.             switch(mode) {
  256.               case M_INSIDE:  x  += dx; y  += dy;    break;
  257.               case M_TOP:      y  += dy; ys -= dy;    break;
  258.               case M_BOTTOM:  ys += dy;        break;
  259.               case M_LEFT:      x  += dx; xs -= dx;    break;
  260.               case M_RIGHT:      xs += dx;        break;
  261.               case M_XMID:      xm  = item->xm + dx;    break;
  262.               case M_YMID:      ym  = item->ym + dy;    break;
  263.             }
  264.             if (x  < 0)    x  = 0;        x  = XSNAP(x);
  265.             if (y  < 0)    y  = 0;        y  = XSNAP(y);
  266.             if (xs < 0)    xs = 0;        xs = XSNAP(xs);
  267.             if (ys < 0)    ys = 0;        ys = XSNAP(ys);
  268.             if (xm > xs)    xm = xs;    xm = XSNAP(xm);
  269.             if (ym > ys)    ym = ys;    ym = XSNAP(ym);
  270.         }
  271.     }
  272.     if (!strcmp(args[0], "motion")) {
  273.         if (moving && (event->state & Button1Mask))
  274.         switch(mode) {
  275.           case M_XMID: draw_rubberband(TRUE, xm+x, y, 1, ys); break;
  276.           case M_YMID: draw_rubberband(TRUE, x, ym+y, xs, 1); break;
  277.           default:     draw_rubberband(TRUE, x, y, xs, ys);
  278.         }
  279.     } else if (!strcmp(args[0], "up")) {
  280.         draw_rubberband(FALSE, 0, 0, 0, 0);
  281.         if (mode == M_OUTSIDE) {
  282.             set_cursor(canvas, XC_arrow);
  283.             return;
  284.         }
  285.         if (mode == M_DIVIDER) {
  286.             int dy = form->ydiv;
  287.             form->ydiv = event->y <  0        ? 0 :
  288.                      event->y >= form->ys ? form->ys-1
  289.                               : event->y;
  290.             form->ydiv = YSNAP(form->ydiv);
  291.             dy = form->ydiv - dy;
  292.             for (i=0; i < form->nitems; i++)
  293.                 form->items[i]->y += dy;
  294.             redraw_canvas();
  295.             set_cursor(canvas, XC_arrow);
  296.             return;
  297.         }
  298.         item = form->items[nitem];
  299.         for (nsel=i=0; i < form->nitems; i++)
  300.             nsel += form->items[i]->selected;
  301.         if (moving) {                    /* moved */
  302.             item->x  = x;
  303.             item->y  = y;
  304.             item->xs = xs;
  305.             item->ys = ys;
  306.             item->xm = xm;
  307.             item->ym = ym;
  308.             redraw_canvas();
  309.         } else {                    /* selected */
  310.             readback_formedit();
  311.             if (state & ShiftMask) {
  312.                 item->selected ^= TRUE;        /*... multi */
  313.                 curr_item = nitem;
  314.             } else {
  315.                 if (!item->selected || nsel > 1) {
  316.                     item_deselect(form);    /*... sel */
  317.                     item->selected = TRUE;
  318.                     curr_item = nitem;
  319.                 } else {
  320.                     item_deselect(form);    /*... unsel */
  321.                     curr_item = form->nitems;
  322.                 }
  323.             }
  324.             redraw_canvas_item(item);
  325.             fillout_formedit();
  326.             sensitize_formedit();
  327.         }
  328.         set_cursor(canvas, XC_arrow);
  329.     }
  330. }
  331.  
  332.  
  333. /*
  334.  * find the item the mouse is in or nearby, and return exactly in which way
  335.  * it is close (left, right, top, bottom). Return the item if found, and the
  336.  * edge found as one of M_*. This is done when the mouse is pressed down, to
  337.  * find out what should be done, and to set the cursor shape.
  338.  */
  339.  
  340. static MOUSE locate_item(
  341.     int        *nitem_p,    /* set to the located item */
  342.     int        x,        /* position in drawing area */
  343.     int        y)
  344. {
  345.     int        nitem;        /* current item number */
  346.     register ITEM    *item;        /* current item, form->items[nitem] */
  347.     int        xc, yc;        /* current item's center pos */
  348.     int        dx, dy;        /* current is this far away from x/y */
  349.     int        cdx=8, cdy=8;    /* closest is this far away from x/y */
  350.     int        closest = -1;    /* closest item so far */
  351.  
  352.                             /* divider? */
  353.     if (y > form->ydiv - DIV_GRIPSZ/2 &&
  354.         y < form->ydiv + DIV_GRIPSZ/2 &&
  355.         x > form->xs - DIV_GRIPOFF - DIV_GRIPSZ/2 &&
  356.         x < form->xs - DIV_GRIPOFF + DIV_GRIPSZ/2)
  357.         return(M_DIVIDER);
  358.                             /* find closest */
  359.     for (nitem=0; nitem < form->nitems; nitem++) {
  360.         item = form->items[nitem];
  361.                                 /* inside? */
  362.         if (item->x+3 <= x && item->x + item->xs-3 > x &&
  363.             item->y+3 <= y && item->y + item->ys-3 > y) {
  364.             closest = nitem;
  365.             break;
  366.         }
  367.         dx = dy = 999;                    /* close? */
  368.         if (y >= item->y && y < item->y+item->ys) {
  369.             dy = cdy;
  370.             if (x <  item->x+3)         dx = item->x+3-x;
  371.             if (x >= item->x+item->xs-3) dx = x-item->x-item->xs+3;
  372.         }
  373.         if (x >= item->x && x < item->x+item->xs) {
  374.             dx = cdx;
  375.             if (y <  item->y+3)         dy = item->y+3-y;
  376.             if (y >= item->y+item->ys-3) dy = y-item->y-item->ys+3;
  377.         }
  378.         if (dx <= cdx && dy <= cdy) {
  379.             cdx = dx;
  380.             cdy = dy;
  381.             closest = nitem;
  382.         }
  383.     }
  384.     if (closest < 0)
  385.         return(M_OUTSIDE);
  386.     if (nitem_p)
  387.         *nitem_p = closest;
  388.     item = form->items[closest];
  389.     if (nitem == closest) {                    /* inside */
  390.         if ((item->type == IT_INPUT ||
  391.              item->type == IT_PRINT ||
  392.              item->type == IT_TIME) && abs(x - item->x - item->xm) < 6)
  393.             return(M_XMID);
  394.  
  395.         if ((item->type == IT_VIEW  ||
  396.              item->type == IT_CHART ||
  397.              item->type == IT_NOTE) && abs(y - item->y - item->ym) < 6)
  398.             return(M_YMID);
  399.  
  400.         return(M_INSIDE);
  401.     }
  402.     xc = item->x + item->xs/2;                /* near edge */
  403.     yc = item->y + item->ys/2;
  404.     dx = x < xc ? abs(x - item->x) : abs(x - item->x-item->xs);
  405.     dy = y < yc ? abs(y - item->y) : abs(y - item->y-item->ys);
  406.  
  407.     if (dx < dy && x <  xc)        return(M_LEFT);
  408.     if (dx < dy && x >= xc)        return(M_RIGHT);
  409.     if (dy < dx && y <  yc)        return(M_TOP);
  410.     if (dy < dx && y >= yc)        return(M_BOTTOM);
  411.     return(M_OUTSIDE); /* paranoid */
  412. }
  413.  
  414.  
  415. /*
  416.  * draw or undraw a rubber band box into the canvas, using XOR drawing. This
  417.  * must be called in draw-undraw pairs.
  418.  */
  419.  
  420. static void draw_rubberband(
  421.     BOOL        draw,        /* draw or undraw */
  422.     int        x,        /* position of box */
  423.     int        y,
  424.     int        xs,        /* size of box */
  425.     int        ys)
  426. {
  427.     static BOOL    is_drawn;    /* TRUE if rubber band exists */
  428.     static int    lx,ly,lxs,lys;    /* drawn rubberband */
  429.  
  430.     if (is_drawn) {
  431.         is_drawn = FALSE;
  432.         XDrawRectangle(display, XtWindow(canvas), xor_gc,
  433.                         lx, ly, lxs, lys);
  434.     }
  435.     if (!draw)
  436.         return;
  437.  
  438.     XDrawRectangle(display, XtWindow(canvas), xor_gc,
  439.                     lx=x-1, ly=y-1, lxs=xs+1, lys=ys+1);
  440.     is_drawn = TRUE;
  441. }
  442.  
  443.  
  444. /*-------------------------------------------------- drawing ----------------*/
  445. /*
  446.  * draw all items in the current form
  447.  */
  448.  
  449. void redraw_canvas(void)
  450. {
  451.     int         i;
  452.  
  453.     if (!have_shell)
  454.         return;
  455.     set_color(COL_CANVBACK);
  456.     XFillRectangle(display, XtWindow(canvas), gc, 0,0, form->xs, form->ys);
  457.  
  458.     for (i=0; i < form->nitems; i++)
  459.         redraw_canvas_item(form->items[i]);
  460.  
  461.     set_color(COL_CANVFRAME);
  462.     XFillRectangle(display, XtWindow(canvas), gc, 0,
  463.                 form->ydiv - DIV_WIDTH/2, form->xs, DIV_WIDTH);
  464.     XFillRectangle(display, XtWindow(canvas), gc,
  465.                 form->xs - DIV_GRIPOFF - DIV_GRIPSZ/2,
  466.                 form->ydiv - DIV_GRIPSZ/2,
  467.                 DIV_GRIPSZ, DIV_GRIPSZ);
  468.     set_color(COL_CANVBACK);
  469.     XFillRectangle(display, XtWindow(canvas), gc,
  470.                 form->xs - DIV_GRIPOFF - DIV_GRIPSZ/2 + 2,
  471.                 form->ydiv - DIV_GRIPSZ/2 + 2,
  472.                 DIV_GRIPSZ - 4, DIV_GRIPSZ - 4);
  473. }
  474.  
  475.  
  476. void undraw_canvas_item(
  477.     register ITEM    *item)        /* item to redraw */
  478. {
  479.     set_color(COL_CANVBACK);
  480.     XFillRectangle(display, XtWindow(canvas), gc,
  481.                     item->x, item->y, item->xs, item->ys);
  482. }
  483.  
  484.  
  485. char *itemname[NITEMS] = {
  486.     "None", "Label", "Print", "Input", "Time", "Note", "Choice", "Flag",
  487.     "Button", "Summary", "Chart" };
  488. static char *datatext[NITEMS] = {
  489.     "None", "", "Print", "Input", "Time", "Note", "", "", "", "Card", "" };
  490.  
  491. void redraw_canvas_item(
  492.     register ITEM    *item)        /* item to redraw */
  493. {
  494.     Window        window = XtWindow(canvas);
  495.     char        buf[1024];    /* truncated texts */
  496.     int        xm=-1, ym=-1;    /* middle division pos */
  497.     int        nfont;        /* font number as FONT_* */
  498.     char        sumcol[20];    /* summary column indicator msg */
  499.     int        n, i;        /* for chart grid lines */
  500.  
  501.     if (!have_shell)
  502.         return;
  503.  
  504.     draw_rubberband(FALSE, 0, 0, 0, 0);
  505.     set_color(item->selected ? COL_CANVSEL : COL_CANVBOX);
  506.     XFillRectangle(display, window, gc,
  507.                     item->x, item->y, item->xs, item->ys);
  508.  
  509.     set_color(COL_CANVFRAME);
  510.  
  511.     XDrawRectangle(display, window, gc,
  512.                 item->x, item->y, item->xs-1, item->ys-1);
  513.     if (item->type == IT_INPUT || item->type == IT_PRINT
  514.                    || item->type == IT_TIME)
  515.         XFillRectangle(display, window, gc,
  516.                 item->x + (xm=item->xm), item->y, 1, item->ys);
  517.  
  518.     if (item->type == IT_CHART || item->type == IT_VIEW
  519.                    || item->type == IT_NOTE)
  520.         XFillRectangle(display, window, gc,
  521.                 item->x, item->y + (ym=item->ym), item->xs, 1);
  522.  
  523.     if (item->type == IT_CHART) {
  524.         int ny = 10;
  525.         int nx = 15 - ny;
  526.         set_color(COL_CANVBACK);
  527.         for (n=1; n < ny; n++) {
  528.             i = item->y + ym + n * (item->ys - ym) / ny,
  529.             XDrawLine(display, window, gc,
  530.                         item->x + 1,            i,
  531.                         item->x + item->xs - 2, i);
  532.         }
  533.         for (n=1; n < nx; n++) {
  534.             i = item->x + n * item->xs / nx;
  535.             XDrawLine(display, window, gc,
  536.                         i, item->y + ym + 1,
  537.                         i, item->y + item->ys - 3);
  538.         }
  539.     }
  540.  
  541.     set_color(COL_CANVTEXT);
  542.     *buf = 0;
  543.     sprintf(sumcol, item->sumwidth ? ",%d" : "", item->sumcol);
  544.     if (item->type == IT_CHOICE || item->type == IT_FLAG)
  545.         sprintf(buf, "[%d=%s%s] ", item->column,
  546.                 item->flagcode ? item->flagcode : "?", sumcol);
  547.     strcat(buf, item->label ? item->label : "label");
  548.     nfont = ifont(item->labelfont);
  549.     truncate_string(buf, xm<0 ? item->xs-4 : xm-4, nfont);
  550.     XSetFont(display, gc, font[nfont]->fid);
  551.     XDrawString(display, window, gc,
  552.             item->x + 3,
  553.             item->y + ((ym>=0?ym:item->ys)+font[nfont]->ascent)/2,
  554.             buf, strlen(buf));
  555.  
  556.     *buf = 0;
  557.     if (IN_DBASE(item->type))
  558.         sprintf(buf, "[%d%s] ", item->column, sumcol);
  559.     strcat(buf, datatext[item->type]);
  560.     if (xm > 0 && xm < item->xs) {
  561.         nfont = ifont(item->inputfont);
  562.         truncate_string(buf, item->xs-xm-4, nfont);
  563.         XSetFont(display, gc, font[nfont]->fid);
  564.         XDrawString(display, window, gc,
  565.             item->x + xm + 3,
  566.             item->y + (item->ys + font[nfont]->ascent)/2,
  567.             buf, strlen(buf));
  568.  
  569.     } else if (ym > 0 && ym < item->ys) {
  570.         nfont = ifont(item->type == IT_NOTE ? item->inputfont
  571.                             : item->labelfont);
  572.         truncate_string(buf, item->xs-4, nfont);
  573.         XSetFont(display, gc, font[nfont]->fid);
  574.         XDrawString(display, window, gc,
  575.             item->x + 3,
  576.             item->y + ym + (item->ys - ym + font[nfont]->ascent)/2,
  577.             buf, strlen(buf));
  578.     }
  579.     set_color(COL_STD);
  580. }
  581.  
  582.  
  583. static int ifont(
  584.     FONTN        fontn)
  585. {
  586.     switch(fontn) {
  587.       default:
  588.       case F_HELV:        return(FONT_HELV);
  589.       case F_HELV_O:    return(FONT_HELV_O);
  590.       case F_HELV_S:    return(FONT_HELV_S);
  591.       case F_HELV_L:    return(FONT_HELV_L);
  592.       case F_COURIER:    return(FONT_COURIER);
  593.     }
  594. }
  595.